CAM scripting/es

Introducción

El Entorno de Trabajo CAM ofrece herramientas para importar, crear, manipular y exportar trayectorias de herramientas de máquinas G-code en FreeCAD. Con este, el usuario puede importar, visualizar y modificar programas G-code existentes, generar trayectorias de herramientas a partir de formas 3D y exportarlas a G-code.

Este entorno se encuentra actualmente en fase de desarrollo inicial y no ofrece todas las funciones avanzadas presentes en algunas alternativas comerciales. Sin embargo, su interfaz de programación en Python facilita la modificación y el desarrollo de herramientas más potentes.

Inicio rapido

Los objetos Path de FreeCAD se componen de una secuencia de comandos de movimiento. Un uso típico sería el siguiente:

>>> import Path
>>> c1 = Path.Command("g1x1")
>>> c2 = Path.Command("g1y4")
>>> c3 = Path.Command("g1 x2 y2") # spaces end newlines are ignored
>>> p = Path.Path([c1,c2,c3])
>>> o = App.ActiveDocument.addObject("Path::Feature","mypath")
>>> o.Path = p
>>> print (p.toGCode())

Formato interno del código G de FreeCAD

Es importante comprender un concepto preliminar. La mayor parte de la implementación que se muestra a continuación se basa en comandos de movimiento con nombres idénticos a los de los comandos de código G, pero que no están diseñados para ser idénticos a la implementación de un controlador específico. Se eligieron nombres como "G0" para representar el movimiento rápido o "G1" para representar el movimiento de avance, con el fin de optimizar el rendimiento (ahorro eficiente de archivos) y minimizar el trabajo necesario para la conversión a/desde otros formatos de código G. Dado que el mundo del CNC utiliza miles de dialectos de código G, se seleccionó un subconjunto muy simplificado. El formato de código G de FreeCAD podría describirse como una forma de código G independiente de la máquina.

Dentro de los archivos .FCStd, los datos de ruta se guardan directamente en ese formato de código G.

Todas las traducciones de dialectos a código G de FreeCAD se realizan mediante scripts previos y posteriores. Esto significa que si desea trabajar con una máquina que utiliza un controlador LinuxCNC, Fanuc, Mitsubishi o HAAS específico, deberá usar (o escribir, si no existe) un posprocesador para ese controlador en particular (consulte la sección "Importación y exportación de código G" a continuación).

Referencia de código G

Las siguientes reglas y directrices definen el subconjunto de código G utilizado internamente en FreeCAD:

Los datos de código G, dentro de los objetos de ruta de FreeCAD, se dividen en "comandos". Un comando se define mediante un nombre que debe comenzar con G o M y (opcionalmente) argumentos, que tienen el formato letra seguida de un número decimal, por ejemplo X 0.02, Y 3.5 o F 300. Estos son ejemplos de comandos típicos de código G en FreeCAD:

G0 X2.5 Y0 (El nombre del comando es G0, los argumentos son X=2.5 e Y=0)
G1 X30 (El nombre del comando es G1, el único argumento es X=30)
G90 (El comando se llama G90 y no tiene argumentos)

Se admiten comandos de código G distintos de los que aparecen en la tabla siguiente; es decir, se guardan dentro de los datos de la trayectoria (siempre que cumplan las reglas anteriores, por supuesto), pero no producirán ningún resultado visible en pantalla. Por ejemplo, se puede añadir un comando G81; se almacenará, pero no se mostrará.

Lista de comandos G-code compatibles actualmente

Comando Descrición Argumentos soportados Mostrado
G0 movimiento rápido X,Y,Z,A,B,C Rojo
G1 movimiento normal X,Y,Z,A,B,C Verde
G2 arco en sentido horario X,Y,Z,A,B,C,I,J,K Verde
G3 arco en sentido antihorario X,Y,Z,A,B,C,I,J,K Verde
G81, G82, G83 Perforar X,Y,Z,R,Q Rojo/verde
G38.2 Movimiento recto de la sonda (utilizado en el funcionamiento de la sonda) Z,F Amarillo
G90 Coordenadas absolutas
G91 Coordenadas relativas
(Message) comentario

El Comando objeto

El comando objeto representa un comando de código G. Tiene tres atributos: Nombre, Parámetros y Posición, y dos métodos: toGCode() y setFromGCode(). Internamente, solo contiene un nombre y un diccionario de parámetros. El resto (posición y código G) se calcula a partir de estos datos.

>>> import Path
>>> c=Path.Command()
>>> c
Command  ( )
>>> c.Name = "G1"
>>> c
Command G1 ( )
>>> c.Parameters= {"X":1,"Y":0}
>>> c
Command G1 ( X:1 Y:0 )
>>> c.Parameters
{'Y': 0.0, 'X': 1.0}
>>> c.Parameters= {"X":1,"Y":0.5}
>>> c
Command G1 ( X:1 Y:0.5 )
>>> c.toGCode()
'G1X1Y0.5'
>>> c2=Path.Command("G2")
>>> c2
Command G2 ( )
>>> c3=Path.Command("G1",{"X":34,"Y":1.2})
>>> c3
Command G1 ( X:34 Y:1.2 )
>>> c3.Placement
Placement [Pos=(34,1.2,0), Yaw-Pitch-Roll=(0,0,0)]
>>> c3.toGCode()
'G1X34Y1.2'
>>> c3.setFromGCode("G1X1Y0")
>>> c3
Command G1 [ X:1 Y:0 ]
>>> c4 = Path.Command("G1X4Y5")
>>> c4
Command G1 [ X:4 Y:5 ]
>>> p1 = App.Placement()
>>> p1.Base = App.Vector(3,2,1)
>>> p1
Placement [Pos=(3,2,1), Yaw-Pitch-Roll=(0,0,0)]
>>> c5=Path.Command("g1",p1)
>>> c5
Command G1 [ X:3 Y:2 Z:1 ]
>>> p2=App.Placement()
>>> p2.Base = App.Vector(5,0,0)
>>> c5
Command G1 [ X:3 Y:2 Z:1 ]
>>> c5.Placement=p2
>>> c5
Command G1 [ X:5 ]
>>> c5.x
5.0
>>> c5.x=10
>>> c5
Command G1 [ X:10 ]
>>> c5.y=2
>>> c5
Command G1 [ X:10 Y:2 ]

El objeto Trayectoria

El objeto Trayectoria (Path) contiene una lista de comandos.

>>> import Path
>>> c1=Path.Command("g1",{"x":1,"y":0})
>>> c2=Path.Command("g1",{"x":0,"y":2})
>>> p=Path.Path([c1,c2])
>>> p
Path [ size:2 length:3 ]
>>> p.Commands
[Command G1 [ X:1 Y:0 ], Command G1 [ X:0 Y:2 ]]
>>> p.Length
3.0
>>> p.addCommands(c1)
Path [ size:3 length:4 ]
>>> p.toGCode()
'G1X1G1Y2G1X1'

lines = """
G0X-0.5905Y-0.3937S3000M03
G0Z0.125
G1Z-0.004F3
G1X0.9842Y-0.3937F14.17
G1X0.9842Y0.433
G1X-0.5905Y0.433
G1X-0.5905Y-0.3937
G0Z0.5
"""

slines = lines.split('\n')
p = Path.Path()
for line in slines:
    p.addCommands(Path.Command(line))

o = App.ActiveDocument.addObject("Path::Feature","mypath")
o.Path = p

# but you can also create a path directly form a piece of G-code.
# The commands will be created automatically:

p = Path.Path()
p.setFromGCode(lines)

Como atajo, también se puede crear un objeto Path directamente a partir de una secuencia completa de código G. Este se dividirá automáticamente en una secuencia de comandos.

>>> p = Path.Path("G0 X2 Y2 G1 X0 Y2")
>>> p
Path [ size:2 length:2 ]

La caracteristica Trayectoria

La característica Ruta es un objeto del documento de FreeCAD que contiene una ruta y la representa en la vista 3D.

>>> pf = App.ActiveDocument.addObject("Path::Feature","mypath")
>>> pf
<Document object>
>>> pf.Path = p
>>> pf.Path
Path [ size:2 length:2 ]

La característica Trayectoria también incluye una propiedad de Posicionamiento. Al cambiar el valor de esta propiedad, se modificará la posición de la función en la vista 3D, aunque la información de la trayectoria en sí no se verá afectada. La transformación es puramente visual. Esto permite, por ejemplo, crear una trayectoria alrededor de una cara con una orientación específica en el modelo, distinta a la que tendrá el material de corte en la máquina CNC.

Sin embargo, las Trayectorias Compuestas pueden utilizar la ubicación de sus hijos (ver más abajo).

La Herramienta y tabla de herramientas objetos


NOTE: This type of tool usage is depreciated as of the 0.19 official release. In 0.19 the new ToolBit tool system was implemented to supersede this older, Legacy, system. Therefore, coding has changed from what is represented below. Please visit CAM Tools page for more information.

Scripting <= 0.18

The Tool object contains the definitions of a CNC tool. The Tooltable object contains an ordered list of tools. Tooltables are attached as a property to Path Project features, and can also be edited via the GUI, by double-clicking a project in the Tree View, and clicking the "Edit tooltable" button in the task views that opens.

From that dialog, tooltables can be imported from FreeCAD's .xml and HeeksCad's .tooltable formats, and exported to FreeCAD's .xml format.

>>> import Path
>>> t1=Path.Tool()
>>> t1
Tool Default tool
>>> t1.Name = "12.7mm Drill Bit"
>>> t1
Tool 12.7mm Drill Bit
>>> t1.ToolType
'Undefined'
>>> t1.ToolType = "Drill"
>>> t1.Diameter= 12.7
>>> t1.LengthOffset = 127
>>> t1.CuttingEdgeAngle = 59
>>> t1.CuttingEdgeHeight = 50.8
>>> t2 = Path.Tool("my other tool",tooltype="EndMill",diameter=10)
>>> t2
Tool my other tool
>>> t2.Diameter
10.0
>>> table = Path.Tooltable()
>>> table
Tooltable containing 0 tools
>>> table.addTools(t1)
Tooltable containing 1 tools
>>> table.addTools(t2)
Tooltable containing 2 tools
>>> table.Tools
{1: Tool 12.7mm Drill Bit, 2: Tool my other tool}
>>>

Características

La característica del Compuesto de Trayectoria

The aim of this feature is to gather one or more toolpaths and associate it (them) with a tooltable. The Compound feature also behaves like a standard FreeCAD group, so you can add or remove objects to/from it directly from the Tree View. You can also reorder items by double-clicking the Compound object in the Tree View, and reorder its elements in the Task view that opens.

>>> import Path
>>> p1 = Path.Path("G1X1")
>>> o1 = App.ActiveDocument.addObject("Path::Feature","path1")
>>> o1.Path=p1
>>> p2 = Path.Path("G1Y1")
>>> o2 = App.ActiveDocument.addObject("Path::Feature","path2")
>>> o2.Path=p2
>>> o3 = App.ActiveDocument.addObject("Path::FeatureCompound","compound")
>>> o3.Group=[o1,o2]

An important feature of Path Compounds is the possibility to take into account the Placement of their child paths or not, by setting their UsePlacements property to True or False. If not, the Path data of their children will simply be added sequentially. If True, each command of the child paths, if containing position information (G0, G1, etc..) will first be transformed by the Placement before being added.

Creating a compound with just one child path allows you therefore to turn the child path's Placement "real" (it affects the Path data).

The Path Project feature

The Path project is an extended kind of Compound, that has a couple of additional machine-related properties such as a tooltable. It is made mainly to be the main object type you'll want to export to G-code once your whole path setup is ready. The Project object is now coded in Python, so its creation mechanism is a bit different:

>>> from PathScripts import PathProject
>>> o4 = App.ActiveDocument.addObject("Path::FeatureCompoundPython","prj")
>>> PathProject.ObjectPathProject(o4)
>>> o4.Group = [o3]
>>> o4.Tooltable
Tooltable containing 0 tools

The Path module also features a GUI tooltable editor that can be called from Python, giving it an object that has a ToolTable property:

>>> from PathScripts import TooltableEditor
>>> TooltableEditor.edit(o4)

Obtención de la trayectoria de la forma

Assign the shape of wire Part to a normal Path object, using Path.fromShape() script function (or more powerful Path.fromShapes()). By giving as parameter a wire Part object, its path will be automatically calculated from the shape. Note that in this case the placement is automatically set to the first point of the wire, and the object is therefore not movable anymore by changing its placement. To move it, the underlying shape itself must be moved.

>>> import Part
>>> import Path
>>> v1 = FreeCAD.Vector(0,0,0)
>>> v2 = FreeCAD.Vector(0,2,0)
>>> v3 = FreeCAD.Vector(2,2,0)
>>> v4 = FreeCAD.Vector(3,3,0)
>>> wire = Part.makePolygon([v1,v2,v3,v4])
>>> o = FreeCAD.ActiveDocument.addObject("Path::Feature","myPath2")
>>> o.Path = Path.fromShape(wire)
>>> FreeCAD.ActiveDocument.recompute()
>>> p =  o.Path
>>> print(p.toGCode())

Características de Python

Both Path::Feature and Path::FeatureShape features have a Python version, respectively named Path::FeaturePython and Path::FeatureShapePython, that can be used in Python code to create more advanced parametric objects derived from them.

Importación y exportación de GCode

Formato nativo

G-code files can be directly imported and exported via the GUI, by using the "open", "insert" or "export" menu items. After the file name is acquired, a dialog pops up to ask which processing script must be used. It can also be done from Python:

Path information is stored into Path objects using a subset of G-code described in the "FreeCAD's internal G-code format"section above. This subset can be imported or exported "as is", or converted to/from a particular version of G-code suited for your machine.

If you have a very simple and standard G-code program, that complies to the rules described in the "FreeCAD's internal G-code format" section above, for example the boomerang from cnccookbook, it can be imported directly into a Path object, without translation (this is equivalent to using the "None" option of the GUI dialog):

import Path
f = open("/path/to/boomerangv4.ncc")
s = f.read()
p = Path.Path(s)
o = App.ActiveDocument.addObject("Path::Feature","boomerang")
o.Path = p

In the same manner, you can obtain the path information as "agnostic" G-code, and store it manually in a file:

text = o.Path.toGCode()
print text
myfile = open("/path/to/newfile.ngc")
myfile.write(text)
myfile.close()

If you need a different output, though, you will need to convert this agnostic G-code into a format suited for your machine. That is the job of post-processing scripts.

Using pre- and post-processing scripts

If you have a G-code file written for a particular machine, which doesn't comply to the internal rules used by FreeCAD, described in the "FreeCAD's internal G-code format" section above, it might fail to import and/or render properly in the 3D View. To remedy to this, you must use a pre-processing script, which will convert from your machine-specific format to the FreeCAD format.

If you know the name of the pre-processing script to use, you can import your file using it, from the Python Console like this:

import example_pre
example_pre.insert("/path/to/myfile.ncc","DocumentName")

In the same manner, you can output a Path object to G-code, using a post_processor script like this:

import example_post
example_post.export (myObjectName,"/path/to/outputFile.ncc")

Writing processing scripts

Pre- and post-processing scripts behave like other common FreeCAD imports/exporters. When choosing a pre/post processing script from the dialog, the import/export process will be redirected to the specified given script. Preprocessing scripts must contain at least the following methods open(filename) and insert(filename,docname). Postprocessing scripts need to implement export(objectslist,filename).

Scripts are placed into either the Mod/Path/Path/Post/scripts folder or the user's macro path directory. You can give them any name you like but by convention, and to be picked by the GUI dialog, pre-processing scripts names must end with "_pre", post-processing scripts with "_post" (make sure to use the underscore, not the hyphen, otherwise Python cannot import it). This is an example of a very, very simple preprocessor. More complex examples are found in the Mod/Path/Path/Post/scripts folder:

def open(filename):
    gfile = __builtins__.open(filename)
    inputstring = gfile.read()
    # the whole gcode program will come in as one string,
    # for example: "G0 X1 Y1\nG1 X2 Y2"
    output = ""
    # we add a comment
    output += "(This is my first parsed output!)\n"
    # we split the input string by lines
    lines = inputstring.split("\n")
    for line in lines:
        output += line
        # we must insert the "end of line" character again
        # because the split removed it
        output += "\n"
    # another comment
    output += "(End of program)"
    import Path
    p = Path.Path(output)
    myPath = FreeCAD.ActiveDocument.addObject("Path::Feature","Import")
    myPath.Path = p
    FreeCAD.ActiveDocument.recompute()

Pre- and post-processors work exactly the same way. They just do the contrary: The pre scripts convert from specific G-code to FreeCAD's "agnostic" G-code, while post scripts convert from FreeCAD's "agnostic" G-code to machine-specific G-code.

Añadir todas las caras de una CadenaForma a la lista de CaracterísticaBase de una operación PerfilDeCaras

This example is based on a discussion in the german forum.

Prerrequisitos

  • Create a solid with ShapeString as Cutout
  • Create a Job using this solid as its BaseObject
  • Create a ProfileFromFaces operation named "Profile_Faces" with empty BaseGeometry.

El código

The following code will then add all faces from ShapeString and create the paths:

doc = App.ActiveDocument
list_of_all_element_faces = []
for i, face in enumerate(doc.ShapeString.Shape.Faces):
    list_of_all_element_faces.append('Face' + str(i + 1))

doc.Profile_Faces.Base = [(doc.ShapeString, tuple(list_of_all_element_faces))]
doc.recompute()